(function($) {
	$.fn.xSelector = function(config) {
		var cfg = $.extend( {
			optionTag : 'p',
			html: '',
			onchange : new Function()
		}, config || {});
		return this.each(function() {
			this.setAttribute('autocomplete', 'off');
			new _selector(cfg, this);
		});
	};
	var _selector = function(cfg, input) {
		var _self = this;
		this.cfg = cfg;
		this.cache = $.extend( {}, {
			inx : 0,
			input : $(input),
			box : null,
			mask : null
		});
		this.genLayout();
		this.bindInputEve();
		this.hide();
		$(' body').click(function() {
			_self.hide();
		});
	};
	$.extend(
					_selector.prototype,
					{
						genLayout : function() {
							var html = [
									'<iframe id="selectorMask" frameborder="0" src="about:blank" scrolling="no" class="mask"></iframe>',
									'<div id="selectorBox" class="autosuggest"></div>' ];
							if ($('#selectorMask').length == 0) {
								$('html>body').append(html.join(''));
							}
							this.cache.box = $('#selectorBox');
							this.cache.mask = $('#selectorMask');
						},
						updateList : function(html) {
							this.cache.box.find(this.cfg.optionTag).unbind();
							this.cache.box.html(html);
							this.cache.box.find(this.cfg.optionTag).each(function(inx){
								this.setAttribute('inx', inx);
							});
							this.bindOptEve();
							this.show();
						},
						show : function() {
							var box   = this.cache.box,
								input = this.cache.input,
								w     = input.outerWidth() + 30;
							if ($.browser.msie && $.browser.version == '6.0')
								box.css('width',w + 'px');
							if(box.css('zIndex') == 'auto'){box.css('zIndex', 100);}
							box.add(this.cache.mask).show().css(
								{
									left : input.offset().left - 1 + 'px',
									top : input.offset().top + input.outerHeight() + 'px',
									minWidth : w + 'px',
									maxHeight: '200px',
									overflow: 'auto'
								}).eq(1).css( {
								width : w + 'px',
								height : box.outerHeight() + 'px',
								zIndex : box.css('zIndex') - 1
							});
						},
						hide : function() {
							this.cache.box.hide();
							this.cache.mask.hide();
							this.cache.box.find(this.cfg.optionTag+'.selected')
									.removeClass('selected');
							this.cache.inx = 0;
						},
						bindOptEve : function() {
							var _self = this;
							var opts = this.cache.box.find(this.cfg.optionTag);
							opts.click(
								function(e) {
									_self.hide();
									_self.inputVal(_self.cache.input, $(this).text());
									_self.cache.inx = parseInt(this.getAttribute('inx'));
								})
								.mouseover(function(e) {
									var node = $(this);
									if(node.hasClass('selected')) return;
									opts.eq(_self.cache.inx).removeClass('selected');
									node.addClass('selected');
									_self.cache.inx = parseInt(this.getAttribute('inx'));
								});
						},
						navOptByKey : function(k) {
							var inx = 0,
								preInx = this.cache.inx,
								opts = this.cache.box.find(this.cfg.optionTag),
								len = opts.length;
							if ($.inArray(k, [ 13, 38, 40 ]) == -1)
								return;
							if (this.cache.box.css('display') == 'none')
								return;
							if (k == 38) {
								inx = preInx - 1;
								if (inx < 0)
									inx = len - 1;
							} else if (k == 40) {
								inx = preInx + 1;
								if (inx >= len)
									inx = 0;
							} else if (k == 13) {
								this.inputVal(this.cache.input, opts.eq(preInx)
										.text());
								this.hide();
								return;
							}
							opts.eq(preInx).removeClass('selected');
							opts.eq(inx).addClass('selected');
							this
									.inputVal(this.cache.input, opts.eq(inx)
											.text());
							this.cache.inx = inx;
						},
						bindInputEve : function() {
							var _self = this, input = this.cache.input;
							input.click(function(e) {
								e.stopPropagation();
								_self.updateList(_self.cfg.html);
							}).keydown(function(e) {
								_self.navOptByKey(e.keyCode);
							});
						},
						inputVal : function(input, val) {
							var rVal = '';
							if (input[0].tagName.toLowerCase() == 'input') {
								rVal = input.val(val);
							} else if (input.attr('contentEditable') == 'true') {
								rVal = input.text(val);
							} else if ($('[contentEditable="true"]', input).length > 0) {
								rVal = $('[contentEditable="true"]', input).eq(0).text(val);
							}
							if (val
									&& val != undefined
									&& val != this.cache.box.find(
											this.cfg.optionTag).eq(
											this.cache.inx).text()) {
								this.cfg.onchange.call(input, val);
							}
							return rVal;
						}
					});
})(jQuery);